using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Security.Cryptography;
using System.Xml.Serialization;
using System.Collections.Specialized;


// Description needed by Son of SmartPart
[System.ComponentModel.Description("LTI Tool Consumer Sakai Spec WebPart")]
public partial class LaunchPartSakai : System.Web.UI.UserControl
{
    // Constants
    const string cWebMethod = "POST";
    const string cWebContentType = "application/x-www-form-urlencoded";

    // Local variables
    private const string defaultText = "";
    // These are defaults for testing purposes only
    private string _providerURL = "http://simplelti.appspot.com/launch";
    private string _sharedSecret = "secret";
    private string _tpResourceId = "http://www.learngauge.com/ScormTest3.zip";
    private string _courseID;
    private string _courseName = "Test Course";
    private string _toolID;
    private string _signature;

    private bool _debug = false;
    private string _debugPost;
    private string _debugResponse;

    // Name Value Collection to hold the parameters sent in post
    private NameValueCollection PostFields = new NameValueCollection();

    private bool debug = false;

    // Properties
    [Browsable(true), Category("Tool Provider URL"), Description("Tool Provider URL")]
    public string ProviderURL
    {
        get { return _providerURL; }
        set { _providerURL = value; }
    }

    [Browsable(true), Category("Shared Secret"), Description("Tool Provider Shared Secret")]
    public string SharedSecret
    {
        get { return _sharedSecret; }
        set { _sharedSecret = value; }
    }

    [Browsable(true), Category("TP Resource ID"), Description("TP Resource ID")]
    public string TPResourceID
    {
        get { return _tpResourceId; }
        set { _tpResourceId = value; }
    }

    [Browsable(true), Category("Course ID"), Description("Course ID")]
    public string CourseID
    {
        get { return _courseID; }
        set { _courseID = value; }
    }

    [Browsable(true), Category("Course Name"), Description("Course Name")]
    public string CourseName
    {
        get { return _courseName; }
        set { _courseName = value; }
    }

    [Browsable(true), Category("Tool ID"), Description("Tool ID")]
    public string ToolID
    {
        get { return _toolID; }
        set { _toolID = value; }
    }


    [Browsable(true), Category("Launch Signature"), Description("Launch Signature")]
    public string Signature
    {
        get { return _signature; }
        set { _signature = value; }
    }



    // Page Load
    protected void Page_Load(object sender, EventArgs e)
    {

        ifrContent.Visible = false; // Hide iFrame
        lblStatus.Text = string.Empty; // Clear Status Text
        pnlwidget.Visible = false; // Hide Widget panel
    }

    // On launch click 
    protected void btnLaunch_Click(object sender, EventArgs e)
    {
        string responseFromToolProvider = string.Empty;
        // Fill in values
        FillData();

        // Post data
        responseFromToolProvider = SendPostData();

        // Parse Response
        ParseData(responseFromToolProvider);
    }

    // Utility function that fills in the name value pairs
    private void FillData()
    {
        string nonce = GetNonce();
        string dateStamp = GetDateStamp();

                        
        AddParameter("action", "launchresolve");
        AddParameter("sec_nonce",nonce);
        AddParameter("sec_digest",GetDigest(nonce,dateStamp,_sharedSecret));
        AddParameter("sec_org_digest", GetSHA(GetOrgID()));
        AddParameter("sec_created",dateStamp);
        AddParameter("user_id",GetUserID());
        AddParameter("user_email", GetUserEmail());
        AddParameter("user_role",GetUserRole());
        AddParameter("user_firstname",GetUserFirstName());
        AddParameter("user_lastname",GetUserLastName());
        AddParameter("user_fullname", GetUserLastName() + ", " + GetUserFirstName());
        AddParameter("user_displayid", GetUserLastName() + ", " + GetUserFirstName());
        AddParameter("user_locale", "en_US");
        AddParameter("user_roster", "1444");
        AddParameter("course_id",GetCourseID());
        AddParameter("course_name", GetCourseName());
        AddParameter("course_title", GetCourseName());
        AddParameter("launch_targets", "post,widget,iframe");
        AddParameter("launch_resource_id",_tpResourceId);
        //AddParameter("launch_resource_url", "http://www.dr-chuck.com/");
        //AddParameter("launch_tool_name", "IMS");
        //AddParameter("launch_tool_title", "IMS");
        AddParameter("launch_tool_id", _toolID);
        AddParameter("launch_tool_signature", _signature);
        AddParameter("launch_width", "320");
        AddParameter("launch_height", "240");
        AddParameter("org_id", GetOrgID());
        //AddParameter("org_title", "IMS");
        //AddParameter("org_name", "IMS");
        //AddParameter("org_url", "http://www.imsglobal.org");
         
    }

    // Utility function that adds name/value pair only if it has data
    private void AddParameter(string name, string value)
    {
        if (!string.IsNullOrEmpty(name)
            && !string.IsNullOrEmpty(value))
        {
            PostFields.Add(name, value);
        }
    }

    // Security Function to create nonce (Just a GUID in our case)
    private string GetNonce()
    {
        System.Guid nonce = System.Guid.NewGuid();
        return nonce.ToString();
    }

    // Utility Function for security
    private string GetDateStamp()
    {
        DateTime dateStamp = DateTime.Now;
        return dateStamp.ToString("yyyy-MM-ddTHH:mm:sszzzz");
    }

    // Security Function to get SHA1 Digest from nonce, datestamp and secret
    private string GetDigest(string nonce, string dateStamp, string secret)
    {
        String presha1 = nonce + dateStamp + secret;
        return GetSHA(presha1);

    }
    private string GetSHA(string presha1)
    {
        
        String sha1 = null;
        try
        {
            UTF8Encoding encoding = new UTF8Encoding();
            byte[] hashBytes = encoding.GetBytes(presha1);

            // compute SHA-1 hash.
            SHA1 md = new SHA1CryptoServiceProvider();
            byte[] cryptstr = md.ComputeHash(hashBytes);

            try
            {
                sha1 = Convert.ToBase64String(cryptstr);   
            }
            catch (Exception e)
            {
                throw new Exception("Error in base64Encode" + e.Message);
            }
        }
        catch (NotSupportedException)
        {
        }

        return sha1;
        
    }

    // User and Course Functions
    private string GetUserID()
    {
        string userID = string.Empty;
        userID = "12";
        return userID;
    }

    private string GetUserEmail()
    {
        string email = string.Empty;
        email = "user@test.com";
        return email;
    }
    private string GetUserFirstName()
    {
        string userName = string.Empty;
        userName = "Test";
        return userName;
    }

    private string GetUserLastName()
    {
        string userName = string.Empty;
        userName = "User";
        return userName;
    }

    private string GetUserRole()
    {
        string userRole = "Student";
        return userRole;
    }

    // This is set as a property of the Web Part
    private string GetCourseID()
    {
        string courseID;
        courseID = System.Guid.NewGuid().ToString();
        return courseID;
    }

    // This is set as a property of the Web Part
    private string GetCourseName()
    {

        return _courseName;
    }

    private string GetOrgID()
    {
        return "IMS";
    }


    // Function to actually compose and send message to the tool
    private string SendPostData()
    {
        String response = string.Empty;

        // Create URI and request
        Uri URI = new Uri(_providerURL);
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(URI);

        // Request Type
        webRequest.Method = cWebMethod;

        // Headers
        webRequest.ContentType = cWebContentType;

        // Parameters
        ASCIIEncoding encoding = new ASCIIEncoding();
        StringBuilder sb = new StringBuilder();
        foreach (string name in PostFields.AllKeys)
        {
            sb.Append(name);
            sb.Append("=");
            sb.Append(HttpUtility.UrlEncode(PostFields[name]));
            //sb.Append("\r\n");
            sb.Append("&");
        }

        byte[] buffer = encoding.GetBytes(sb.ToString());

        //
        if (_debug) lblPost.Text = "<pre>" + sb.ToString() + "</pre>";

        
        // Get length of content
        webRequest.ContentLength = buffer.Length;

        // Get request stream
        Stream newStream = webRequest.GetRequestStream();

        // Send the data.
        newStream.Write(buffer, 0, buffer.Length);

        // Close stream
        newStream.Close();

        // Assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
        HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

        // Display the contents of the page to the console.
        Stream streamResponse = webResponse.GetResponseStream();

        // Get stream object
        StreamReader streamRead = new StreamReader(streamResponse);

        Char[] readBuffer = new Char[256];

        // Read from buffer
        int count = streamRead.Read(readBuffer, 0, 256);
        
        while (count > 0)
        {
            // get string
            String resultData = new String(readBuffer, 0, count);

            response += resultData;

            // Read from buffer
            count = streamRead.Read(readBuffer, 0, 256);
        }

        // Release the response object resources.
        streamRead.Close();
        streamResponse.Close();

        // Close response
        webResponse.Close();
        
        //
        if (_debug) lblResponse.Text = "<pre>" + response + "</pre>";

        return response;
    }


    // Function to parse the response from the tool and determine if it is a widget, or iframe
    private void ParseData(string response)
    {
        string status = string.Empty;
        string launchType = string.Empty;
        string launchData = string.Empty;
        // Parse XML return data
        XmlDocument x = new XmlDocument();
        XmlNodeList xnl;
        x.Load(new StringReader(response));

        // Check for Status
        xnl = x.SelectNodes("//status");
        status = GetNodeList(xnl);

        // If failed then show error
        if (status.ToLower() != "success")
        {
            xnl = x.SelectNodes("//code");
            lblStatus.Text = GetNodeList(xnl);
            lblStatus.Text += " - ";
            xnl = x.SelectNodes("//description");
            lblStatus.Text += GetNodeList(xnl);
        }
        else // If success then determine widget or iFrame
        {
            xnl = x.SelectNodes("//type");
            launchType = GetNodeList(xnl);
            if (launchType.ToLower() == "iframe")
            {
                xnl = x.SelectNodes("//launchUrl");
                launchData = GetNodeList(xnl);
                ifrContent.InnerHtml = launchData;
                ifrContent.Attributes["src"] = launchData;
                ifrContent.Visible = true;
            }

            if (launchType.ToLower() == "widget")
            {
                xnl = x.SelectNodes("//widget");
                launchData = GetNodeList(xnl);
                pnlwidget.Controls.Add(new LiteralControl(launchData));
                pnlwidget.Visible = true;
            }
        }

        if (debug) Response.Write("<pre>" + Server.HtmlEncode(response) + "</pre>");
    }

    // Utility Function to get all values in a node/nodelist
    private string GetNodeList(XmlNodeList xnl)
    {
        string nodeValue = string.Empty;
        foreach (XmlNode xNode in xnl)
        {
            nodeValue += xNode.InnerText;
        }
        return nodeValue;
    }

    
}
